package com.wzdigit.wms.wms.service.order;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.wzdigit.framework.Shift;
import com.wzdigit.mes.basic.api.BasicSimpleCodeRuleApi;
import com.wzdigit.mes.sys.api.UserApiService;
import com.wzdigit.mes.sys.dto.UserDto;
import com.wzdigit.wms.basic.client.PagerInfo;
import com.wzdigit.wms.basic.client.request.asn.other.*;
import com.wzdigit.wms.basic.client.response.Result;
import com.wzdigit.wms.basic.client.response.asn.other.*;
import com.wzdigit.wms.basic.domain.asn.AsnDtl;
import com.wzdigit.wms.basic.domain.asn.AsnDtlGoods;
import com.wzdigit.wms.basic.domain.asn.AsnHeader;
import com.wzdigit.wms.basic.domain.basic.Sku;
import com.wzdigit.wms.basic.domain.dtos.inventory.UpdateInventoryInputDto;
import com.wzdigit.wms.basic.domain.inventory.Goods;
import com.wzdigit.wms.basic.domain.inventory.GoodsPkg;
import com.wzdigit.wms.basic.domain.inventory.InvTrans;
import com.wzdigit.wms.basic.domain.inventory.Lotno;
import com.wzdigit.wms.basic.domain.order.DocLog;
import com.wzdigit.wms.basic.domain.order.TrsnDtl;
import com.wzdigit.wms.basic.domain.order.TrsnDtlGoods;
import com.wzdigit.wms.basic.domain.order.TrsnHeader;
import com.wzdigit.wms.basic.enums.*;
import com.wzdigit.wms.basic.mapper.core.basic.SkuMapper;
import com.wzdigit.wms.basic.service.code.InventoryService;
import com.wzdigit.wms.basic.service.code.LotnoService;
import com.wzdigit.wms.basic.util.StringUtils;
import com.wzdigit.wms.wms.service.across.CallbackService;
import com.wzdigit.wms.wms.service.core.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OtherStockInService {

    @Autowired
    private AsnManagerService asnManagerService;
    @Autowired
    private SkuMapper skuMapper;
    @Autowired
    private GoodsService goodsService;
    @Autowired
    private TrsnManagerService trsnManagerService;
    @Autowired
    private InventoryService inventoryService;
    @Reference(version = "${dubbo.consumers.basic.simple.code.rule.api:1.0.0}", check = false)
    private BasicSimpleCodeRuleApi basicSimpleCodeRuleApi;
    @Autowired
    private LotnoService lotnoService;
    @Autowired
    private DocLogService docLogService;
    @Autowired
    private CallbackService callbackService;

    @Reference(version = "${dubbo.consumers.sys.user.api.version:1.0.0}", check = false, timeout = 300000)
    private UserApiService userApiService;

    final String trsnRuleCode = "TRSN_ORDER";
    final String palletNoRuleCode = "virtualPalletCode";

    /**
     * 搜索单据
     *
     * @param input xxx
     * @param <T>   xx
     * @return
     */
    public <T> PagerInfo<List<OtherInOrderInfoResponse>> search(SearchOtherInOrderRequest input) {
        Page<T> page = PageHelper.offsetPage(input.getSkipCount(), input.getMaxResultCount());

        PagerInfo<List<OtherInOrderInfoResponse>> pagerInfo = new PagerInfo<>();
        List<OtherInOrderInfoResponse> list = this.asnManagerService.selectOtherTaskInfo(input);
        Map<String, String> userNames = new HashMap<>();

        for (OtherInOrderInfoResponse item : list) {
            AsnTypeEnum enumByCode = AsnTypeEnum.getEnumByCode(item.getAsnType());
            if (enumByCode != null) {
                item.setAsnTypeName(enumByCode.getEnumName());
            }

            AsnHeaderStatusEnum enumByCode1 = AsnHeaderStatusEnum.getEnumByCode(item.getStatus());
            if (enumByCode1 != null) {
                item.setStatusName(enumByCode1.getEnumName());
            }
            //获取用户  
            if (!userNames.containsKey(item.getCreateUser())) {
                UserDto userByUsername = this.userApiService.getUserByUsername(item.getCreateUser());
                if (userByUsername == null) {
                    userNames.put(item.getCreateUser(), item.getCreateUser());
                } else {
                    if (userByUsername.getUserId() == null)
                        userNames.put(item.getCreateUser(), item.getCreateUser());
                    else
                        userNames.put(item.getCreateUser(), userByUsername.getName());
                }
            }
            item.setCreateUser(userNames.get(item.getCreateUser()));
        }
        pagerInfo.setItems(list);
        pagerInfo.setTotalCount(page.getTotal());

        return pagerInfo;
    }


    /**
     * 扫描工单
     *
     * @param billNo 单据号
     * @return 信息
     */
    public ScanOtherInOrderResponse scanOrder(String billNo) {
        //1. 获取订单信息
        AsnHeader asnHeader = this.asnManagerService.getAsnHeaderService().selectByNo(billNo);
        if (asnHeader == null) {
            Shift.fatal(String.format("没有找到单号[%s]的信息！", billNo));
        }
        if (!(asnHeader.getAsnType().equals(AsnTypeEnum.R04.getCode())
                || asnHeader.getAsnType().equals(AsnTypeEnum.R99.getCode())
                || asnHeader.getAsnType().equals(AsnTypeEnum.R08.getCode())
                || asnHeader.getAsnType().equals(AsnTypeEnum.R09.getCode())
                || asnHeader.getAsnType().equals(AsnTypeEnum.R10.getCode()))) {
            Shift.fatal(String.format("单据[%s]不属于其他入库范围！", billNo));
        }
        if (asnHeader.getStatus().equals(AsnHeaderStatusEnum.FINISH.getCode())) {
            Shift.fatal(String.format("单据[%s]已完成,无需继续操作！", billNo));
        }
        //2. 获取明细
        List<AsnDtl> asnDtlList = this.asnManagerService.getAsnDtlService().selectListByAsnNo(asnHeader.getAsnNo());
        if (asnDtlList.size() == 0) {
            Shift.fatal(String.format("没有找到单号[%s]的明细信息！", billNo));
        }
        asnDtlList.forEach(t -> {
            if (t.getRcvQty() == null) {
                t.setRcvQty(BigDecimal.ZERO);
                t.setRcvQtyEa(BigDecimal.ZERO);
            }
        });
        ScanOtherInOrderResponse ret = new ScanOtherInOrderResponse();
        ret.setAsnNo(asnHeader.getAsnNo());
        ret.setSourceNo(asnHeader.getSourceNo());
        ret.setWhsId(asnHeader.getToWhs());
        ret.setOwner(asnHeader.getOwner());
        ret.setStatus(asnHeader.getStatus());
        ret.setStatusName(AsnHeaderStatusEnum.getEnumByCode(asnHeader.getStatus()).getEnumName());
        ret.setFactory(asnHeader.getFactory());
        ret.setAsnType(asnHeader.getAsnType());
        ret.setAsnTypeName(AsnTypeEnum.getEnumByCode(ret.getAsnType()).getEnumName());
        ret.setCustomer(asnHeader.getIssuePartyName());
        ret.setPlanQty(asnDtlList.stream().map(AsnDtl::getOrderQty).reduce(BigDecimal.ZERO, BigDecimal::add));
        ret.setSubQty(asnDtlList.stream().map(AsnDtl::getRcvQty).reduce(BigDecimal.ZERO, BigDecimal::add));
        ret.setReplaceWhs(asnHeader.getStatus().equals(AsnHeaderStatusEnum.CREATE.getCode()));
        for (AsnDtl asnDtl : asnDtlList) {

            if (ret.getWhsId() == null) {
                ret.setWhsId(asnDtl.getWhsId());
            }

            Sku sku = this.skuMapper.selectById(asnDtl.getSkuId());

            ScanOtherInOrderItemsResponse item = new ScanOtherInOrderItemsResponse();
            if (StringUtils.isNull(asnDtl.getLotno())) {
                Lotno lotno = lotnoService.getLotnoByAsnDtlId(asnDtl.getAsnDtlId());
                item.setLotNo(lotno == null ? null : lotno.getLotno());
            } else {
                item.setLotNo(asnDtl.getLotno());
            }
            item.setId(asnDtl.getAsnDtlId());
            item.setRowIndex(asnDtl.getAsnLineNo());
            item.setPoNo(asnDtl.getPoNo());
            item.setSkuId(asnDtl.getSkuId());
            item.setSkuDesc(asnDtl.getSkuDesc());
            item.setSkuCode(sku.getSkuCode());
            item.setStatus(asnDtl.getStatus());
            item.setStatusName(AsnDtlStatusEnum.getEnumByCode(asnDtl.getStatus()).getEnumName());
            item.setPlanQty(asnDtl.getOrderQty());
            item.setSubQty(asnDtl.getRcvQty());
            ret.getItems().add(item);
        }
        //TODO 获取数据字典扩展中对单据类型的能否进行无sn扫描收货开关
        ret.setSnScan(true);
        return ret;
    }

    /**
     * @param input 输入
     * @param <T>   类型
     * @return 输出
     */
    public <T> PagerInfo<List<OtherInOrderGoodsResponse>> searchOrderGoods(
            SearchOtherInOrderGoodsRequest input) {
        Page<T> page = PageHelper.offsetPage(input.getSkipCount(), input.getMaxResultCount());

        PagerInfo<List<OtherInOrderGoodsResponse>> pagerInfo = new PagerInfo<>();

        List<OtherInOrderGoodsResponse> list = this.asnManagerService.selectGoodsByNo(input);

        pagerInfo.setItems(list);
        pagerInfo.setTotalCount(page.getTotal());

        return pagerInfo;
    }

    /**
     * @param input
     * @return
     */
    public Result<ScanOtherInSnResponse> scanSn(SearchOtherInSnRequest input) {
		input.getCanMatchItems().removeIf(Objects::isNull);
		List<SearchOtherInCanMatchItemRequest> canMatchItems = input.getCanMatchItems();
		if (canMatchItems.size() == 0) {
			Shift.fatal("传参错误!");
		}
        
        // 获取sn信息
        Goods goods = goodsService.selectBySn(input.getSn());
        if (AsnTypeEnum.R04.getCode().equals(input.getAsnType())) {
            if (goods != null) {
            	Shift.fatal("当前sn未销售出库!");
            }
            List<Goods> goodsList = goodsService.selectGoodsByHisSn(input.getSn());
            if (goodsList.size() == 0) {
            	Shift.fatal("没有销售的sn记录!");
            }
            goods = goodsList.get(0);
        }
        if (goods == null) {
            List<Goods> goodsList = goodsService.selectGoodsByHisSn(input.getSn());
            if (goodsList.size() == 0) {
                Shift.fatal(String.format("没有找到sn[%s]的信息!", input.getSn()));
            }
            goods = goodsList.get(0);
        }
        
        if (goods.getWhsId() != null) {
            Shift.fatal(String.format("当前SN[%s]已经在仓库了!", input.getSn()));
        }
        AsnHeader asnHeader = asnManagerService.getAsnHeaderService().selectByNo(input.getAsnNo());
        if (!asnHeader.getOwner().equals(goods.getOwner())) {
        	Shift.fatal("sn所属组织与单据所属货主不一致!");
        }
        if (asnHeader.getFactory() == null) {
            Shift.fatal("单据的组织不能为空!");
        }
        if (!asnHeader.getFactory().equals(goods.getFactory())) {
        	Shift.fatal("sn所属组织与单据所属组织不一致!");
        }

        // 获取明细行
        List<Integer> asnDtlIdList = canMatchItems.stream().map(SearchOtherInCanMatchItemRequest::getId).collect(Collectors.toList());
        List<AsnDtl> asnDtlList = asnManagerService.getAsnDtlService().selectListByIds(asnDtlIdList);

        Sku sku = skuMapper.selectById(goods.getSkuId());
        
        ScanOtherInSnResponse ret = new ScanOtherInSnResponse();
        ret.setGoodsSn(goods.getGoodsSn());
        ret.setPoNo(goods.getPoNo());
        ret.setSkuCode(sku.getSkuCode());
        ret.setSkuId(goods.getSkuId());
        ret.setSkuDesc(sku.getDescCn());
        ret.setQty(goods.getQty());
        
        //2. 判断sn属于哪个明细行
        for (AsnDtl asnDtl : asnDtlList) {
            if (goods.getQaStatus().equals(QaStatusEnum.WAIT.getCode())) {
            	// 条码的QA状态=待检，则设置合格
            	goods.setQaStatus(QaStatusEnum.OK.getCode());
            }
            
            if (!ret.getSkuId().equals(asnDtl.getSkuId())) {
            	// 条码的物料跟收货单明细的物料不一致
            	continue;
            }
            
            SearchOtherInCanMatchItemRequest canMatchItem = canMatchItems.stream().filter(t -> t.getId().equals(asnDtl.getAsnDtlId())).findFirst().orElse(null);
            if (canMatchItem == null) {
            	// 没找到相同ID的收货单明细
            	continue;
            }
            
            if (asnDtl.getRcvQty() == null) {
            	asnDtl.setRcvQty(BigDecimal.ZERO);
            }
            if (asnDtl.getOrderQty().subtract(asnDtl.getRcvQty()).compareTo(goods.getQty()) < 0) {
            	// 未收货数量 < 条码的数量
            	continue;
            }
            
            if (!goods.getLotno().equals(canMatchItem.getLotNo())) {
            	// 批次号不一致
            	continue;
            }
            if (!goods.getQaStatus().equals(asnDtl.getQaStatus())) {
            	// QA状态不一致
            	continue;
            }
            ret.setAsnDtlId(canMatchItem.getId());
            break;
        }
        if (ret.getAsnDtlId() == null) {
        	Shift.fatal(String.format("sn[%s]没有匹配到对应的明细!", goods.getGoodsSn()));
        }


        return new Result<>(ret);
    }

    /**
     * 提交数据
     *
     * @param input
     * @throws Exception 
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public boolean submit(SubmitOtherInInputRequest input) throws Exception {
        boolean isClose = false;
        //1. 获取入库单
        AsnHeader asnHeader = this.asnManagerService.getAsnHeaderService().selectByNo(input.getAsnNo());
        if (asnHeader == null) {
            Shift.fatal("没有找到收货单信息!");
        }
        if (asnHeader.getStatus().equals(AsnHeaderStatusEnum.FINISH.getCode())
                || asnHeader.getStatus().equals(AsnHeaderStatusEnum.CANCEL.getCode())
        ) {
            Shift.fatal("订单已完成/已取消,不允许进行收货!");
        }
        asnHeader.setModifyUser(input.getUserName());
        //1.1 收货明细
        List<AsnDtl> asnDtlList = this.asnManagerService.getAsnDtlService().selectListByAsnNo(input.getAsnNo());

        List<TrsnDtl> trsnDtlList = new ArrayList<>();
        Integer toWhsId = input.getWhsId();
        if (asnHeader.getStatus() == AsnHeaderStatusEnum.CREATE.getCode()) {
            asnHeader.setToWhs(toWhsId);
        } else {
            if (asnHeader.getToWhs() == null)
                Shift.fatal("单据仓库为空!");
            if (!asnHeader.getToWhs().equals(toWhsId))
                Shift.fatal("单据收货仓库与选择仓库不一致!");
        }
        //1.2 入库凭证
        TrsnHeader trsnHeader = this.setTrsnHeader(asnHeader);

        asnDtlList.forEach(asnDtl -> {
            asnDtl.setWhsId(toWhsId);
            if (asnDtl.getRcvQty() == null) {
                asnDtl.setRcvQty(BigDecimal.ZERO);
                asnDtl.setRcvQtyEa(BigDecimal.ZERO);
            }
            trsnDtlList.add(this.setTrsnDtl(asnHeader, asnDtl));
        });
        //1.3 获取sn信息
        List<String> snList = input.getSnItems().stream()
                .filter(SubmitOtherInItemRequest::isScan).map(SubmitOtherInItemRequest::getSn)
                .distinct().collect(Collectors.toList());
        List<AsnDtlGoods> asnDtlGoodsList = new ArrayList<>();
        List<Goods> goodsList = this.getGoodsList(asnHeader.getAsnType(), snList);
        if (snList.size() > 0) {
            if (goodsList.size() != snList.size()) {
                List<String> existSn = goodsList.stream().map(Goods::getGoodsSn).distinct().collect(Collectors.toList());
                List<String> notExistSn = snList.stream().filter(t -> !existSn.contains(t)).collect(Collectors.toList());
                Shift.fatal("以下sn没有找不到信息:[" + String.join(",", notExistSn) + "]");
            }
            List<String> whsGoodsList = goodsList.stream().filter(t -> t.getWhsId() != null).map(Goods::getGoodsSn).collect(Collectors.toList());
            if (whsGoodsList.size() > 0) {
                Shift.fatal("以下sn已经在仓库中:[" + String.join(",", whsGoodsList) + "]");
            }
            input.getSnItems().stream().filter(SubmitOtherInItemRequest::isScan).forEach(snItem -> {
                AsnDtl asnDtl = asnDtlList.stream().filter(t -> t.getAsnDtlId().equals(snItem.getAsnDtlId())).findFirst().get();
                Goods goods = goodsList.stream().filter(t -> t.getGoodsSn().equals(snItem.getSn())).findFirst().get();
                asnDtlGoodsList.add(this.setAsnDtlGoods(asnHeader, asnDtl, goods));
            });
        }
        //2. 数据处理
        List<Integer> dtlIdList = asnDtlList.stream().map(AsnDtl::getAsnDtlId).collect(Collectors.toList());
        List<BigDecimal> snQtyList = new ArrayList<>();
        List<BigDecimal> noSnQtyList = new ArrayList<>();
        List<List<String>> dtl2snList = new ArrayList<>();
        dtlIdList.forEach(t -> {
            snQtyList.add(BigDecimal.ZERO);
            noSnQtyList.add(BigDecimal.ZERO);
            dtl2snList.add(new ArrayList<>());
            AsnDtl firstAsnDtl = asnDtlList.stream().filter(dtl -> dtl.getAsnDtlId().equals(t)).findFirst().get();
            if (StringUtils.isNull(firstAsnDtl.getLotno())) {
                Lotno lotno = this.lotnoService.getLotnoByAsnDtlId(t);
                firstAsnDtl.setLotno(lotno == null ? null : lotno.getLotno());
            }
        });

        input.getSnItems().forEach(snItem -> {
            //1,修改asnDtl
            AsnDtl firstAsnDtl = asnDtlList.stream().filter(t -> t.getAsnDtlId().equals(snItem.getAsnDtlId())).findFirst().get();
            if (firstAsnDtl.getRcvQty() == null) firstAsnDtl.setRcvQty(BigDecimal.ZERO);
            firstAsnDtl.setRcvQty(firstAsnDtl.getRcvQty().add(snItem.getQty()));
            firstAsnDtl.setRcvTime(new Date());
            //2 修改trsnDtl
            TrsnDtl firstTrsnDtl = trsnDtlList.stream().filter(t -> t.getFmDocLine().equals(firstAsnDtl.getAsnLineNo())).findFirst().get();
            firstTrsnDtl.setQty(firstTrsnDtl.getQty().add(snItem.getQty()));
            Integer index = dtlIdList.indexOf(firstAsnDtl.getAsnDtlId());
            //3. 记录sn
            if (snItem.isScan()) {
                snQtyList.set(index, snQtyList.get(index).add(snItem.getQty()));
                dtl2snList.get(dtlIdList.indexOf(firstAsnDtl.getAsnDtlId())).add(snItem.getSn());
            } else {
                noSnQtyList.set(index, noSnQtyList.get(index).add(snItem.getQty()));
            }
        });
        //判断超收
        for (AsnDtl asnDtl : asnDtlList) {
            if (asnDtl.getOrderQty().compareTo(asnDtl.getRcvQty()) < 0) {
                Shift.fatal("不允许超收!");
            }
        }

        //3. 保存数据
        //3.1 保存表头
        asnHeader.setModifyUser(input.getUserName());
        asnHeader.setModifyTime(new Date());
        if (asnDtlList.stream().filter(t -> t.getOrderQty().equals(t.getRcvQty())).count() == asnDtlList.size()) {
            asnHeader.setStatus(AsnHeaderStatusEnum.FINISH.getCode());
        } else {
            asnHeader.setStatus(AsnHeaderStatusEnum.PARTRECEIVE.getCode());
        }
        asnManagerService.getAsnHeaderService().updateOne(asnHeader);
        //3.2 保存明细
        List<Integer> updateIdList = this.mergeOperation(dtlIdList, snQtyList, noSnQtyList);
        if (updateIdList.size() == 0)
            Shift.fatal("有问题");
        updateIdList.forEach(id -> {
            AsnDtl item = asnDtlList.stream().filter(t -> t.getAsnDtlId().equals(id)).findFirst().get();
            Integer index = dtlIdList.indexOf(id);
            item.setRcvQtyEa(item.getRcvQty());
            item.setModifyTime(new Date());
            item.setModifyUser(input.getUserName());
            if (item.getOrderQty().compareTo(item.getRcvQty()) == 0) {
                item.setStatus(AsnDtlStatusEnum.WHOLERECEIVE.getCode());
            } else {
                item.setStatus(AsnDtlStatusEnum.PARTRECEIVE.getCode());
            }
            this.asnManagerService.getAsnDtlService().updateOne(item);
            //3.6 单据操作日志
            DocLog docLog = this.setDocLog(asnHeader, dtlIdList, snQtyList, noSnQtyList, item);
            docLogService.addNewOne(docLog);
        });
        //3,4 入库凭证
        trsnDtlList.removeIf(t -> t.getQty().compareTo(BigDecimal.ZERO) == 0);
        for (int i = 0; i < trsnDtlList.size(); i++) {
            trsnDtlList.get(i).setNoteLineNo(String.valueOf(i + 1));
            trsnDtlList.get(i).setModifyTime(new Date());
            trsnDtlList.get(i).setModifyUser(input.getUserName());
        }
        this.trsnManagerService.insertTrsnInfo(trsnHeader, trsnDtlList);

        //3.5.1 产生虚拟卡板
        GoodsPkg goodsPkg = this.setGoodsPkg(input.getUserName());
        this.goodsService.getGoodsPkgMapper().insert(goodsPkg);
        goodsPkg.setUrl(String.format("%s_0", goodsPkg.getGoodsPkgId()));
        this.goodsService.getGoodsPkgMapper().updateUrlByGoodsPkgId(goodsPkg.getGoodsPkgId(), goodsPkg.getUrl());

        //3.5.2 sn 挪到库存中/修改仓库
        goodsList.forEach(item -> {
            item.setStatus(GoodsStatusEnum.WAIT_UP.getCode());
            item.setPkgId(goodsPkg.getGoodsPkgId());
            item.setModifyTime(new Date());
            item.setModifyUser(input.getUserName());
            item.setWhsId(asnHeader.getToWhs());
            if (item.getStockInDate() == null) {
                item.setStockInDate(new Date());
            }
            if (asnHeader.getAsnType().equals(AsnTypeEnum.R04.getCode()) || item.getGoodsId() == null) {
                this.goodsService.insertGoods(item);
            } else {
                this.goodsService.updateGoods(item);
            }
        });
        //3.3 保存入库货品明细
        if (asnDtlGoodsList.size() > 0) {
            asnDtlGoodsList.forEach(item -> {
                item.setCreateUser(input.getUserName());
                item.setModifyUser(input.getUserName());
                item.setCreateTime(new Date());
                item.setModifyTime(new Date());
                if (item.getGoodsId() == null) {
                    Goods goods = goodsList.stream().filter(t -> t.getGoodsSn().equals(item.getGoodsSn())).findFirst().orElse(null);
                    if (goods != null) {
                        item.setGoodsId(goods.getGoodsId());
                    }
                }
                this.asnManagerService.getAsnDtlGoodsService().addNewOne(item);
            });
        }
        asnDtlGoodsList.forEach(asnDtlGoods -> {
            AsnDtl firstAsnDtl = asnDtlList.stream().filter(t -> t.getAsnDtlId().equals(asnDtlGoods.getAsnDtlId())).findFirst().get();
            TrsnDtl firstTrsnDtl = trsnDtlList.stream().filter(t -> t.getFmDocLine().equals(firstAsnDtl.getAsnLineNo())).findFirst().get();
            TrsnDtlGoods item = this.setTrsnDtlGoods(firstAsnDtl, firstTrsnDtl, asnDtlGoods);
            this.trsnManagerService.getTrsnDtlGoodsMapper().insert(item);
        });
        //3,6 库存变更
        this.handleInventory(asnHeader, asnDtlList, trsnHeader, trsnDtlList, dtlIdList, snQtyList, noSnQtyList);
        //4. 回传
        if (asnHeader.getStatus().equals(AsnHeaderStatusEnum.FINISH.getCode())) {
            isClose = true;
            this.callbackService.Callback(asnHeader);
        }
        //Shift.fatal("测试,自动回滚!");
        return isClose;
    }

    private GoodsPkg setGoodsPkg(String userName) {
        GoodsPkg goodsPkg = new GoodsPkg();
        goodsPkg.setPkgSn(this.basicSimpleCodeRuleApi.GenerateCode(this.palletNoRuleCode));
        goodsPkg.setPkgLevel(1);
        goodsPkg.setPkgCategory("PALLET");
        goodsPkg.setPkgType(10);
        goodsPkg.setFatherPkgId(0);
        goodsPkg.setIsLeaf(BooleanEnum.TRUE.getCode());
        goodsPkg.setUrl(String.format("%s_0", goodsPkg.getGoodsPkgId()));
        goodsPkg.setCreateTime(new Date());
        goodsPkg.setModifyTime(new Date());
        goodsPkg.setCreateUser(userName);
        goodsPkg.setModifyUser(userName);
        return goodsPkg;
    }

    private void handleInventory(AsnHeader asnHeader, List<AsnDtl> asnDtlList, TrsnHeader trsnHeader, List<TrsnDtl> trsnDtlList, List<Integer> dtlIdList, List<BigDecimal> snQtyList, List<BigDecimal> noSnQtyList) throws Exception {
        for (int i = 0; i < dtlIdList.size(); i++) {
            if (snQtyList.get(i).compareTo(BigDecimal.ZERO) == 0 && noSnQtyList.get(i).compareTo(BigDecimal.ZERO) == 0)
                continue;
            Integer dtlId = dtlIdList.get(i);

            AsnDtl asnDtl = asnDtlList.stream().filter(t -> t.getAsnDtlId().equals(dtlId)).findFirst().get();
            UpdateInventoryInputDto toInput = new UpdateInventoryInputDto();
            toInput.setWhsId(asnDtl.getWhsId());
            toInput.setOwner(asnHeader.getOwner());
            toInput.setSkuId(asnDtl.getSkuId());
            toInput.setFactory(asnHeader.getFactory());
            toInput.setVendorId(asnHeader.getVendorId());
            toInput.setLotNo(asnDtl.getLotno());
            toInput.setInvAttr(asnDtl.getInvAttr());
            toInput.setQaStatus(asnDtl.getQaStatus());
            toInput.setUnit(asnDtl.getUnit());
            toInput.setQty((snQtyList.get(i).add(noSnQtyList.get(i))));
            toInput.setOperator(asnDtl.getModifyUser());

            TrsnDtl trsnDtl = trsnDtlList.stream().filter(t -> t.getFmDocLine().equals(String.valueOf(asnDtl.getAsnLineNo()))).findFirst().get();
            InvTrans log = new InvTrans();
            log.setOpCode(OpCodeEnum.SHIPPED.getCode());
            log.setDocType(asnHeader.getAsnType());
            log.setDocNo(asnHeader.getAsnNo());
            log.setDocLineNo(String.valueOf(asnDtl.getAsnLineNo()));
            log.setTrsnNo(trsnHeader.getNoteNo());
            log.setTrsnLineNo(trsnDtl.getNoteLineNo());
            log.setStatus(InvTransStatusEnum.FINISHED.getCode());
            log.setTransTime(new Date());
            log.setOperator(asnDtl.getModifyUser());
            log.setTransQty((snQtyList.get(i).add(noSnQtyList.get(i))));
            log.setCreateTime(new Date());
            log.setModifyTime(new Date());
            log.setCreateUser(asnDtl.getModifyUser());
            log.setModifyUser(asnDtl.getModifyUser());
            this.inventoryService.inventoryIn(toInput, log);
        }
    }


    private TrsnDtlGoods setTrsnDtlGoods(AsnDtl firstAsnDtl, TrsnDtl firstTrsnDtl, AsnDtlGoods asnDtlGoods) {
        TrsnDtlGoods item = new TrsnDtlGoods();
        item.setTrsnDtlId(firstTrsnDtl.getTrsnDtlId());
        item.setGoodsId(asnDtlGoods.getGoodsId());
        item.setGoodsSn(asnDtlGoods.getGoodsSn());
        item.setQaStatus(asnDtlGoods.getQaStatus());
        item.setQty(asnDtlGoods.getQty());
        item.setComments("");
        item.setStatus(TrsnDtlGoodsStatusEnum.RECEIVED.getCode());
        item.setQaStatus(asnDtlGoods.getQaStatus());
        item.setCreateUser(firstAsnDtl.getModifyUser());
        item.setModifyUser(firstAsnDtl.getModifyUser());
        item.setCreateTime(new Date());
        item.setModifyTime(new Date());
        return item;
    }

    private DocLog setDocLog(AsnHeader asnHeader, List<Integer> dtlIdList, List<BigDecimal> snQtyList, List<BigDecimal> noSnQtyList, AsnDtl item) {
        DocLog docLog = new DocLog();
        docLog.setDocType(asnHeader.getAsnType());
        docLog.setDocNo(asnHeader.getAsnNo());
        docLog.setDocLineNo(String.valueOf(item.getAsnLineNo()));
        docLog.setOpCode(asnHeader.getAsnType().equals(AsnTypeEnum.R04.getCode()) ? "Return" : "Receive");
        docLog.setOperator(item.getModifyUser());
        docLog.setOpTime(new Date());
        docLog.setContent("出库数量增加:" + (snQtyList.get(dtlIdList.indexOf(item.getAsnDtlId())).add(noSnQtyList.get(dtlIdList.indexOf(item.getAsnDtlId())))));
        docLog.setUdf1(item.getUdf1());
        docLog.setUdf2(item.getUdf2());
        docLog.setUdf3(item.getUdf3());
        docLog.setUdf4(item.getUdf4());
        docLog.setUdf5(item.getUdf5());
        docLog.setComments(item.getComments());
        docLog.setCreateTime(new Date());
        docLog.setCreateUser(item.getModifyUser());
        docLog.setModifyTime(new Date());
        docLog.setModifyUser(item.getModifyUser());
        return docLog;
    }

    private List<Integer> mergeOperation(List<Integer> dtlIdList, List<BigDecimal> snQtyList, List<BigDecimal> noSnQtyList) {
        List<Integer> items = new ArrayList<>();
        for (int i = 0; i < dtlIdList.size(); i++) {
            if (snQtyList.get(i).compareTo(BigDecimal.ZERO) == 0 && noSnQtyList.get(i).compareTo(BigDecimal.ZERO) == 0)
                continue;
            Integer id = dtlIdList.get(i);
            items.add(id);
        }
        return items;
    }

    /**
     * 强制关单
     *
     * @param billNo
     * @param userName
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public void close(String billNo, String userName) {
        //1. 获取退货单信息
        AsnHeader asnHeader = this.asnManagerService.getAsnHeaderService().selectByNo(billNo);
        if (asnHeader == null) {
            Shift.fatal("没有找到单据信息！");
        }
        if (asnHeader.getStatus() == AsnHeaderStatusEnum.FINISH.getCode()) {
            Shift.fatal("单据已关闭,不能进行操作！");
        }
        //1.1 获取退货单明细
        List<AsnDtl> asnDtlList = this.asnManagerService.getAsnDtlService().selectListByAsnNo(billNo);

        asnHeader.setStatus(AsnHeaderStatusEnum.FINISH.getCode());
        asnHeader.setModifyTime(new Date());
        asnHeader.setModifyUser(userName);
        this.asnManagerService.getAsnHeaderService().getMapper().updateById(asnHeader);
        for (AsnDtl asnDtl : asnDtlList) {
            if (!asnDtl.getStatus().equals(AsnDtlStatusEnum.FINISH.getCode())) {
                asnDtl.setStatus(AsnDtlStatusEnum.FINISH.getCode());
                asnDtl.setModifyTime(new Date());
                asnDtl.setModifyUser(userName);
                this.asnManagerService.getAsnDtlService().getMapper().updateById(asnDtl);
            }
        }
        this.callbackService.Callback(asnHeader);
    }

    private List<Goods> getGoodsList(String asnType, List<String> snList) {
        if (snList.size() == 0)
            return new ArrayList<>();
        if (asnType.equals(AsnTypeEnum.R04.getCode())) {
            //客户退货
            return this.goodsService.selectGoodsByHisSn(snList);
        }
        //正常入库
        List<Goods> goods = this.goodsService.selectListByListSn(snList);
        //如果获取到的数据与参数数量不一致, 则去历史表中寻找
        if (snList.size() > goods.size()) {
            //获取到未获取到的sn
            List<String> existList = goods.stream().map(Goods::getGoodsSn).collect(Collectors.toList());
            List<String> notExistList = snList.stream().filter(t -> !existList.contains(t)).collect(Collectors.toList());

            List<Goods> list = this.goodsService.selectGoodsByHisSn(notExistList);
            goods.addAll(list);
        }
        goods.forEach(t -> t.setQaStatus(QaStatusEnum.OK.getCode()));
        return goods;
    }

    /**
     * @param asnHeader
     * @param asnItem
     * @param goods
     * @return
     */
    private AsnDtlGoods setAsnDtlGoods(AsnHeader asnHeader, AsnDtl asnItem, Goods goods) {
        AsnDtlGoods item = new AsnDtlGoods();
        item.setAsnDtlId(asnItem.getAsnDtlId());
        item.setGoodsId(goods.getGoodsId());
        item.setGoodsSn(goods.getGoodsSn());
        item.setQaStatus(goods.getQaStatus());
        item.setQty(goods.getQty());
        item.setComments("");
        item.setStatus(AsnDtlGoodsStatusEnum.HAS_RECEIVE.getCode());
        item.setCreateUser(asnHeader.getModifyUser());
        item.setModifyUser(asnHeader.getModifyUser());
        item.setCreateTime(new Date());
        item.setModifyTime(new Date());
        return item;
    }

    /*赋值 TrsnHeader*/
    private TrsnHeader setTrsnHeader(AsnHeader asnHeader) {
        TrsnHeader item = new TrsnHeader();
        item.setNoteNo(basicSimpleCodeRuleApi.GenerateCode(trsnRuleCode));
        item.setNoteType(TrsnNoteTypeEnum.IN_STORAGE.getCode()); //凭证类型
        item.setOwner(asnHeader.getOwner());
        item.setFactory(asnHeader.getFactory());
        item.setWhsId(asnHeader.getToWhs());
        item.setVendorId(asnHeader.getVendorId());
        item.setFmDoc(asnHeader.getAsnNo()); //来源单据
        item.setStatus(TrsnHeaderStatusEnum.CRT.getCode());
        item.setCreateTime(new Date());
        item.setModifyTime(new Date());
        item.setModifyUser(asnHeader.getModifyUser());
        item.setCreateUser(asnHeader.getModifyUser());
        return item;
    }

    /*赋值 TrsnDtl*/
    private TrsnDtl setTrsnDtl(AsnHeader asnHeader, AsnDtl asnDtl) {
        TrsnDtl item = new TrsnDtl();

        item.setNoteLineNo(String.valueOf(asnDtl.getAsnLineNo()));
        item.setInvUpdateFlag(TrsnDtlInvUpdateFlagEnum.IN.getCode());
        item.setFmDoc(asnDtl.getAsnNo());
        item.setFmDocLine(asnDtl.getAsnLineNo());
        item.setSkuId(asnDtl.getSkuId());
        item.setQty(BigDecimal.ZERO);
        item.setUnit(asnDtl.getUnit());
        item.setQaStatus(asnDtl.getQaStatus());
        item.setInvAttr(asnDtl.getInvAttr());
        item.setLotAttr1(asnDtl.getLotAttr1());
        item.setLotAttr2(asnDtl.getLotAttr2());
        item.setLotAttr3(asnDtl.getLotAttr3());
        item.setLotAttr4(asnDtl.getLotAttr4());
        item.setLotAttr5(asnDtl.getLotAttr5());
        item.setLotAttr6(asnDtl.getLotAttr6());
        item.setLotAttr7(asnDtl.getLotAttr7());
        item.setLotAttr8(asnDtl.getLotAttr8());
        item.setLotAttr9(asnDtl.getLotAttr9());
        item.setLotAttr10(asnDtl.getLotAttr10());
        item.setLotAttr11(asnDtl.getLotAttr11());
        item.setLotAttr12(asnDtl.getLotAttr12());
        item.setStatus(TrsnDtlStatusEnum.CRT.getCode());
        item.setCreateTime(new Date());
        item.setModifyTime(new Date());
        item.setModifyUser(asnHeader.getModifyUser());
        item.setCreateUser(asnHeader.getModifyUser());
        return item;
    }

}





























